package com.testmanager.testmananger.shuiyou.strCompare.service;


import com.testmanager.testmananger.foundation.util.FlakeIdGenerator;
import com.testmanager.testmananger.shuiyou.common.util.OtherDataSource;
import com.testmanager.testmananger.shuiyou.strCompare.domain.*;
import com.testmanager.testmananger.shuiyou.strCompare.dto.SyCompareTaskDto;
import com.testmanager.testmananger.shuiyou.strCompare.respository.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import javax.sql.DataSource;
import javax.xml.ws.Response;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
@Service
public class ExceuteTaskService {

    @Autowired
    SyProjectRepository projectRepository;
    @Autowired
    SyCompareTaskRepository compareTaskRepository;
    @Autowired
    SySqlCompareRepository sqlCompareRepository;
    @Autowired
    SyDbManagerRepository syDbManagerRepository;

    @Autowired
    OtherDataSource otherDataSource;

    @Autowired
    SyTaskVariableValueRepository variableValueRepository;
    @Autowired
    SyCompareScriptKeyRepository  scriptKeyRepository;
    @Autowired
    SyCompareResultRepository resultRepository;
    @Autowired
    SyCompareDetailResultRepository detailResultRepository;


    @Autowired
    SqlCompareTaskService   taskService;

    @Autowired
    FlakeIdGenerator flakeIdGenerator;
    /**
     * 1.根据taskid查询所需数据库
     * 2.判断连接池存不存在，不存在则初始化，并放到map中 -- 后续最好不做连接池，直接创建连接
     * 3.查询对应的sqlscript
     * 4.查询srcsql，destsql对应的sql结果
     * 5.根据锚点一个一个查询destsql
     * 6. result  resultdetail
     * @param taskid
     * @return
     */

    public SyCompareResultEntity executeTask(long taskid) throws Exception {
        log.info("executetask,taskid:{}",taskid);

        LocalDateTime time = LocalDateTime.now();

        try {

            //查询数据库
            SyCompareTaskEntity taskEntity = compareTaskRepository.findById(taskid);

            log.info("executeTask,taskEntity:{}",taskEntity);
            SyDbManagerEntity srcDbEntity = syDbManagerRepository.findByDbno(taskEntity.getSrcDbID());
            SyDbManagerEntity destDbEntity = syDbManagerRepository.findByDbno(taskEntity.getDestDbId());
            SySqlCompareScriptEntity sqlCompareScriptEntity = sqlCompareRepository.findByScriptno(taskEntity.getScriptId());
            List<SyTaskVariableValueEntity> variables = variableValueRepository.findAllByTaskId(taskEntity.getTaskno());

            //替换sql变量
            String srcSql = replace(sqlCompareScriptEntity.getSrcSql(),variables);
            String destSql = replace(sqlCompareScriptEntity.getDestSql(),variables);

            //获取组合主键
            List<SyCompareScriptKeyEntity> anchors = scriptKeyRepository.findAllByScriptIdAndType(taskEntity.getScriptId(), 1);


            //验证数据库 初始化数据库
            verifyAndInitDb(srcDbEntity);
            verifyAndInitDb(destDbEntity);


            Map<String,Map<String,String>> srcResultMap = new ConcurrentHashMap<>();
           // Map<String,Map<String,String>> destResultMap = new HashMap<>();

            List<Map<String,String>> srcResult = otherDataSource.getSelectResult(srcDbEntity.getDbname(), sqlCompareScriptEntity.getSrcSql());
            List<Map<String,String>> destResult = otherDataSource.getSelectResult(destDbEntity.getDbname(), sqlCompareScriptEntity.getDestSql());

            //初始化结果
            SyCompareResultEntity resultEntity = new SyCompareResultEntity();



            //异常处理
            /*
            异常处理
                    1.src只有一条数据 ，  dest数据需要> =1 直接与dest第一条数据比对  ，后续不列入结果
                    2.dest为空
                    2.src 无数据
                     3.src有多条数据 ，锚点主键不存在

                     4. anchor  不存在于数据库查询结果时， 未实现

             */
            int srcMount = srcResult.size();
            int destMount = destResult.size();
            int authorMount = anchors.size();
            resultEntity.setSrcTotal(srcMount)
                    .setId(flakeIdGenerator.newId())
                    .setDestTotal(destMount)
                    .setCompareTaskid(taskid)
                    .setSrcSql(sqlCompareScriptEntity.getSrcSql())
                    .setDestSql(sqlCompareScriptEntity.getDestSql())
                    .setExecuteTime(time);
            if(srcMount == 0){
                resultEntity
                        .setDiffCount(destMount)
                        .setComment("源数据查询结果为空，不作比较");
                taskEntity.setResult(1);
                taskEntity.setLastExecuteTime(LocalDateTime.now());
                compareTaskRepository.save(taskEntity);
                return  resultRepository.save(resultEntity);
            }
            if (destMount == 0){
                resultEntity.setDiffCount(srcMount)
                        .setComment("目标数据库查询结果为空，不作比较");
                taskEntity.setResult(1);
                taskEntity.setLastExecuteTime(LocalDateTime.now());
                compareTaskRepository.save(taskEntity);
                return  resultRepository.save(resultEntity);
            }


            if (srcMount > 1 && authorMount == 0 ){
                resultEntity.setComment("源数据查询结果数量大于1且不存在主键，不做比较");
                taskEntity.setResult(1);
                taskEntity.setLastExecuteTime(LocalDateTime.now());
                compareTaskRepository.save(taskEntity);
                return  resultRepository.save(resultEntity);
            }

            if (srcMount == 1 && destMount == 1){

                boolean b = compareMap(srcResult.get(0), destResult.get(0));
                resultEntity.setDiffCount(!b?1:0);

                SyCompareResultEntity save = resultRepository.save(resultEntity);
                SyCompareDetailResultEntity syCompareDetailResultEntity = new SyCompareDetailResultEntity().setResultId(save.getId())
                        .setId(flakeIdGenerator.newId())
                        .setSrcResult(srcResult.get(0).toString())
                        .setDestResult(srcResult.get(0).toString());
                taskEntity.setResult(2);
                taskEntity.setLastExecuteTime(LocalDateTime.now());
                compareTaskRepository.save(taskEntity);
                detailResultRepository.save(syCompareDetailResultEntity);
                return resultEntity;

            }



           resultEntity = resultRepository.save(resultEntity.setCompareTaskid(taskid).setSrcTotal(srcResult.size()).setDestTotal(destResult.size()));

            srcResult.stream().parallel().forEach(t->{
                String tempAnchor = "";
                for (SyCompareScriptKeyEntity anchor : anchors){
                    tempAnchor = "_"+t.get(anchor.getName().trim().toUpperCase());
                }
                srcResultMap.put(tempAnchor,t);
            });

//            log.info("line 156,srcResult:{}",srcResult);
//            log.info("line 157,srcResultMap:{}",srcResultMap);
//            log.info("line 158,destResult:{}",destResult);

            //开始比较
            long resultId = resultEntity.getId();
            AtomicLong diffcount = new AtomicLong();

            destResult.stream().parallel().forEach(t->{
                String tempAnchor = "";
                for (SyCompareScriptKeyEntity anchor : anchors){
                    tempAnchor = "_"+t.get(anchor.getName().trim().toUpperCase());
                }
                if (srcResultMap.containsKey(tempAnchor)){
                    if (!compareMap(t,srcResultMap.get(tempAnchor))){
                        SyCompareDetailResultEntity detailResultEntity = new SyCompareDetailResultEntity();
                        detailResultEntity.setResultId(resultId)
                                .setSrcResult(srcResultMap.get(tempAnchor).toString())
                                .setDestResult(t.toString())
                                .setId(flakeIdGenerator.newId());
                        detailResultRepository.save(detailResultEntity);
                        diffcount.incrementAndGet();
                    }
                    srcResultMap.remove(tempAnchor);



                }else {
                    diffcount.incrementAndGet();
                    SyCompareDetailResultEntity detailResultEntity = new SyCompareDetailResultEntity();
                    detailResultEntity.setSrcResult("未找到相同的")
                            .setDestResult(t.toString())
                            .setId(flakeIdGenerator.newId())
                            .setResultId(resultId);
                    detailResultRepository.save(detailResultEntity);
                }


            });

            resultEntity.setDiffCount(diffcount.get()+srcResultMap.size());
            resultRepository.save(resultEntity);

             srcResultMap.forEach((k,v)->{
                 SyCompareDetailResultEntity detailResultEntity = new SyCompareDetailResultEntity();
                 detailResultEntity.setSrcResult(v.toString())
                         .setDestResult("未找到相同的")
                         .setId(flakeIdGenerator.newId())
                         .setResultId(resultId);
                 detailResultRepository.save(detailResultEntity);

             });

             if(resultEntity.getDiffCount()>0){
                 taskEntity.setResult(1);
             }else{
                 taskEntity.setResult(2);
             }
             taskEntity.setLastExecuteTime(LocalDateTime.now());
            compareTaskRepository.save(taskEntity);
             return  resultEntity;






        }catch (Exception e){

            throw new Exception(e);
        }

    }


    /**
     * 具体开放的对外比对任务方法
     * @param taskid
     * @return
     */
    public ResponseEntity execute(long taskid){
        log.info("executeTask , taskid:{}",taskid);
        try {
            return ResponseEntity.ok(executeTask(taskid));
        } catch (Exception e) {
            log.info("execute task error :{}",e);
            return ResponseEntity.badRequest().body(e);
        }

    }

    public ResponseEntity testExecuteTask(SyCompareTaskDto taskDto){
        log.info("testExecuteTask:taskdto :{}",taskDto);
        SyCompareTaskEntity taskEntity = taskService.saveTask(taskDto);
        execute(taskEntity.getId());

        return null;

    }


    /**
     * 批量比对任务
     * @param tasksid
     * @return
     */

    public ResponseEntity executeTasks( List<SyCompareTaskEntity> tasksid){

        log.info("executeTasks:taskentities:{}",tasksid);

        ExecutorService service = Executors.newFixedThreadPool(5);


        service.execute(new Runnable() {
            @Override
            public void run() {
                for (SyCompareTaskEntity taskid : tasksid){
                    execute(taskid.getId());
                }
            }
        });



        return ResponseEntity.ok("success");

    }


    /**
     * 数据库验证 及 初始化数据库  从容器中获取数据库池，如无此连接池，则创建。
     * @param dbManagerEntity
     * @return
     */
    private  DataSource verifyAndInitDb(SyDbManagerEntity dbManagerEntity){

        log.info("verifyAndInitDb:SyDbManagerEntity:{}",dbManagerEntity);
        DataSource dataSource = null;

        if ( !otherDataSource.getDataSourceMap().containsKey(dbManagerEntity.getDbname())){
             dataSource = otherDataSource.createDataSource(dbManagerEntity.getDbname(), dbManagerEntity.getDriverClass(), dbManagerEntity.getUrl(),
                    dbManagerEntity.getUsername(), dbManagerEntity.getPassword(), dbManagerEntity.getDbtype());
            otherDataSource.getDataSourceMap().put(dbManagerEntity.getDbname(),dataSource);

        }else {
            dataSource = otherDataSource.getDataSourceMap().get(dbManagerEntity.getDbname());
        }

        return dataSource;


    }

    /**
     * 单条任务查询结果比对
     * @param srcMap
     * @param destMap
     * @return
     */
    private  boolean compareMap(Map<String,String> srcMap,Map<String,String> destMap){
        String srcValue = null;
        String destValue = null;
        boolean comapareFlag = true;
        for (String key : srcMap.keySet()){
            srcValue = srcMap.get(key);
            destValue = destMap.get(key);

            if (null == srcValue || null==destValue ||  !srcValue.equals(destValue)){
                comapareFlag = false;
                break;
            }

        }
    return comapareFlag;

    }

    /**
     * 对sql进行参数化处理
     * 将sql的中参数化的值 ${value} 转为正常的值
     * @param sql
     * @param variables
     * @return
     */
    private String replace(String sql,List<SyTaskVariableValueEntity> variables){

        if(variables.size() == 0){
            return  sql;
        }

        String sqltemp = sql;

        Pattern pattern = Pattern.compile("(\\$\\{)([\\w]+)(\\})");
        Matcher matcher = pattern.matcher(sqltemp);

        String findstr = "";
        String key = "";
        while (matcher.find()){
            findstr = matcher.group();
            for (SyTaskVariableValueEntity  variableValueEntity: variables){
                key =  "${"+variableValueEntity.getVarName()+"}";
                if (findstr.equals(key)){
                    sqltemp =  sqltemp.replace( findstr,variableValueEntity.getValue());
                    break;
                }
            }

        }
        return sqltemp;


    }






}
